import { Injectable, Inject } from '../decorators/inject';
import { CellRenderEditManage } from './cell-render-edit-manage';
import { TableDatas } from './table-datas';
import { NExcel } from '../types';
import { NFont } from '../types/style.interface';
import { WholeCol } from './whole-col';
import { Config } from './config';
import { MergeCell } from './merge-cell';
import { FreezeRender } from './freeze-render';
import { Cache } from './cache';
import { FullControl } from './full-control';
@Injectable('CellRender')
export class CellRender implements ICellRender{
    protected ctx: CanvasRenderingContext2D;
    protected freezeInfo = {
        width: 0,
        height: 0,
        startX: 0,
        startY: 0
    }
    constructor(
        protected cellRenderManage: CellRenderEditManage,
        protected tableData: TableDatas,
        @Inject(NExcel.TableDataCanvasToken) protected canvasDataEle: HTMLCanvasElement,
        protected wholeCol: WholeCol,
        protected conf: Config,
        protected mergeCell: MergeCell,
        protected freezeRender: FreezeRender,
        protected cache: Cache,
        protected fullControl: FullControl
        ) {
            this.ctx = this.canvasDataEle.getContext('2d');
    }
    public beforeRender() {
        let w = this.canvasDataEle.clientWidth * this.conf.pixelRatio;
        let h = this.canvasDataEle.clientHeight * this.conf.pixelRatio;
        this.freezeInfo = {
            width: w,
            height: h,
            startX: this.conf.header.row.width + this.freezeRender.getStartColWidth(),
            startY: this.conf.header.col.height + this.freezeRender.getStartRowHeight()
        }
    }
    protected clipArea(x: number, y: number, w: number, h: number, que: number) {
        let res = {x, y, w, h};
        if(que === 1) {
            if(x < this.conf.header.row.width) {
                res.x = this.conf.header.row.width;
                res.w -= (this.conf.header.row.width - x);
            }
            if(res.x + res.w > this.freezeInfo.startX) {
                res.w -= (res.x + res.w) - this.freezeInfo.startX;
            }
            if(res.y < this.conf.header.col.height) {
                res.h -= this.conf.header.col.height - res.y;
                res.y = this.conf.header.col.height;
            }
            if(res.y + res.h > this.freezeInfo.startY) {
                res.h -= res.y + res.h - this.freezeInfo.startY
            }
            return res;
        }
        if(que === 2) {
            if(res.x < this.freezeInfo.startX) {
                res.w -= this.freezeInfo.startX - res.x;
                res.x = this.freezeInfo.startX;
            }
            if(res.x + res.w > this.freezeInfo.width) {
                res.w -= res.x + res.w - this.freezeInfo.width;
            }
            if(res.y < this.conf.header.col.height) {
                res.h -= this.conf.header.col.height - res.y;
                res.y = this.conf.header.col.height;
            }
            if(res.y + res.h > this.freezeInfo.startY) {
                res.h -= res.y + res.h - this.freezeInfo.startY
            }
            return res;
        }
        if(que === 3) {
            if(x < this.conf.header.row.width) {
                res.x = this.conf.header.row.width;
                res.w -= (this.conf.header.row.width - x);
            }
            if(res.x + res.w > this.freezeInfo.startX) {
                res.w -= (res.x + res.w) - this.freezeInfo.startX;
            }
            if(res.y < this.freezeInfo.startY) {
                res.h -= this.freezeInfo.startY - res.y;
                res.y = this.freezeInfo.startY;
            }
            if(res.y + res.h > this.freezeInfo.height) {
                res.h -= res.y + res.h - this.freezeInfo.height;
            }
            return res;
        }
        if(que === 4) {
            if(res.y < this.freezeInfo.startY) {
                res.h -= this.freezeInfo.startY - res.y;
                res.y = this.freezeInfo.startY;
            }
            if(res.y + res.h > this.freezeInfo.height) {
                res.h -= res.y + res.h - this.freezeInfo.height;
            }
            if(res.x < this.freezeInfo.startX) {
                res.w -= this.freezeInfo.startX - res.x;
                res.x = this.freezeInfo.startX;
            }
            if(res.x + res.w > this.freezeInfo.width) {
                res.w -= res.x + res.w - this.freezeInfo.width;
            }
            return res;
        }
        return res;
    }
    protected addPadding(rect: TRect) {
        const opt = {
            padding: {
                top: this.conf.defaultPadding.top * this.conf.enlarge,
                left: this.conf.defaultPadding.left * this.conf.enlarge,
                bottom: this.conf.defaultPadding.bottom * this.conf.enlarge,
                right: this.conf.defaultPadding.right * this.conf.enlarge
            }
        }
        let result = {
            x: rect.x + opt.padding.left,
            y: rect.y + opt.padding.top,
            w: rect.w - opt.padding.left - opt.padding.right,
            h: rect.h - opt.padding.top - opt.padding.bottom
        }
        return result;
    }
    public renderMergeCell(row: number, col: number, rowspan: number, colspan: number) {

    }
    public renderSingleCell(row: number, col: number, que: number) {
        if(!this.tableData.rowIsExist(row)) {
            return;
        }
        let rowInstance = this.tableData.getRow(row);
        rowInstance.updatePosition(row);
        if(!rowInstance.colIsExist(col)) {
            return;
        }
        let cellInstance = rowInstance.getCell(col);
        cellInstance.updatePosition(row, col);
        if(cellInstance && cellInstance.value) {
            let cellPositionRect = this.cache.getRangeRectInfo({row: row, col: col});
            let originRect = this.addPadding({
                x: cellPositionRect.start.x,
                y: cellPositionRect.start.y,
                w: cellPositionRect.w,
                h: cellPositionRect.h
            });
            let font = this.fullControl.getCellFont(row, col, cellInstance.font);
            let cellClipRect = this.clipArea(cellPositionRect.start.x, cellPositionRect.start.y, cellPositionRect.w, cellPositionRect.h, que);
            let cellClipRectWithPadding = this.addPadding({
                x: cellClipRect.x,
                y: cellClipRect.y,
                w: cellClipRect.w,
                h: cellClipRect.h
            });
            cellInstance.getRender().render({...originRect}, cellClipRectWithPadding, font);
        }
    }
    public render(row: number, col: number) {
        let merge = this.mergeCell.getMerge(row, col);
        if(merge) {
            this.renderMergeCell(merge.row, merge.col, merge.rowspan, merge.colspan);
        } else {
            this.renderSingleCell(row, col,0);
        }
    }
}